package org.taobao.ibatiside.db;

import java.sql.Types;
import java.text.SimpleDateFormat;

import org.eclipse.datatools.connectivity.IConnectionProfile;
import org.eclipse.datatools.modelbase.sql.datatypes.BooleanDataType;
import org.eclipse.datatools.modelbase.sql.datatypes.CharacterStringDataType;
import org.eclipse.datatools.modelbase.sql.datatypes.DataType;
import org.eclipse.datatools.modelbase.sql.datatypes.DateDataType;
import org.eclipse.datatools.modelbase.sql.datatypes.NumericalDataType;
import org.eclipse.datatools.modelbase.sql.datatypes.TimeDataType;
import org.eclipse.datatools.modelbase.sql.query.QueryDeleteStatement;
import org.eclipse.datatools.modelbase.sql.query.QueryInsertStatement;
import org.eclipse.datatools.modelbase.sql.query.QuerySelect;
import org.eclipse.datatools.modelbase.sql.query.QuerySelectStatement;
import org.eclipse.datatools.modelbase.sql.query.QueryStatement;
import org.eclipse.datatools.modelbase.sql.query.QueryUpdateStatement;
import org.eclipse.datatools.modelbase.sql.query.TableInDatabase;
import org.eclipse.datatools.modelbase.sql.tables.Table;

public class DTPFacadeImpl implements IDTPFacade {
	public static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd");
	public static final SimpleDateFormat TIME_FORMAT = new SimpleDateFormat("HH:mm:ss");
	public static final SimpleDateFormat TIMESTAMP_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	public static final String STRING_DEFAULT="'foo'";
	public static final String BOOLEAN_DEFAULT="false";
	public static final String NUMBERIC_DEFAULT="1";
	public static final String IEEE754_DEFAULT="1.0";
	public static final String UNSUPPORTED_PROFILE="???";
	public static final String UNSUPPORTED_DATA_TYPE="!!!";
	@Override
	public String getSampleValue(IConnectionProfile profile, DataType type) {
		if (PROFILE_ORACLE.equals(profile.getProviderId())){
			return getSampleValueInOracle(profile,type);
		}else if (PROFILE_MYSQL.equals(profile.getProviderId())){
			return getSampleValueInMySQL(profile,type);
		}else if (PROFILE_MSSQL.equals(profile.getProviderId())){
			return getSampleValueInMSSQL(profile, type);
		}
		return UNSUPPORTED_PROFILE;
	}
	private String getSampleValueInMSSQL(IConnectionProfile profile,
			DataType type) {
		// TODO DC:implement MS SQL Server 
		return null;
	}
	private String getSampleValueInMySQL(IConnectionProfile profile,
			DataType type) {
		if (type instanceof CharacterStringDataType){
			return STRING_DEFAULT;
		}else if (type instanceof BooleanDataType){
			return BOOLEAN_DEFAULT;
		}else if (type instanceof NumericalDataType){
			return NUMBERIC_DEFAULT;
		}else if (type instanceof DateDataType){
			return "'" + DATE_FORMAT.format(new java.util.Date()) + "'";
		}else if (type instanceof TimeDataType){
			if (((TimeDataType) type).getFractionalSecondsPrecision() == 6) {
				return "'" + TIMESTAMP_FORMAT.format(new java.util.Date())
						+ "'";
			} else {
				return "'" + TIME_FORMAT.format(new java.util.Date()) + "'";
			}			
		}
		return UNSUPPORTED_DATA_TYPE;
	}
	private String getSampleValueInOracle(IConnectionProfile profile,
			DataType type) {
		if (type instanceof CharacterStringDataType){
			return STRING_DEFAULT;
		}else if (type instanceof BooleanDataType){
			return BOOLEAN_DEFAULT;
		}else if (type instanceof NumericalDataType){
			return NUMBERIC_DEFAULT;
		}else if (type instanceof DateDataType){
			return "to_date('" + DATE_FORMAT.format(new java.util.Date())
			+ "','yyyy-mm-dd')";
		}else if (type instanceof TimeDataType){
			return "to_timestamp('"
			+ TIMESTAMP_FORMAT.format(new java.util.Date())
			+ "','yyyy-mm-dd hh24:mi:SS')";			
		}
		return UNSUPPORTED_DATA_TYPE;
	}
	@Override
	public String getIdentifierQuoteString(IConnectionProfile profile) {
		if (PROFILE_ORACLE.equals(profile.getProviderId())){
			return "";
		}else if (PROFILE_MYSQL.equals(profile.getProviderId())){
			return "`";
		}else if (PROFILE_MSSQL.equals(profile.getProviderId())){
			
		}
		return "\"";
	}
	@Override
	public Table getOperationalTable(QueryStatement statement) {
		if (statement instanceof QuerySelectStatement){
			QuerySelect query = (QuerySelect) ((QuerySelectStatement)statement).getQueryExpr().getQuery();
			if (query.getFromClause().size() > 0){
				return ((TableInDatabase)query.getFromClause().get(0)).getDatabaseTable();
			}
		}else if (statement instanceof QueryUpdateStatement){
			return ((QueryUpdateStatement)statement).getTargetTable().getDatabaseTable();
		}else if (statement instanceof QueryDeleteStatement){
			return ((QueryDeleteStatement)statement).getTargetTable().getDatabaseTable();
		}else if (statement instanceof QueryInsertStatement){
			return ((QueryInsertStatement)statement).getTargetTable().getDatabaseTable();
		}
		return null;
	}
	
	public String getJavaType(IConnectionProfile profile, int jdbcType){
		if (PROFILE_ORACLE.equals(profile.getProviderId())){
			return getJavaTypeByOracle(profile,jdbcType);
		}else if (PROFILE_MYSQL.equals(profile.getProviderId())){
			return getJavaTypeByMySQL(profile,jdbcType);
		}else if (PROFILE_MSSQL.equals(profile.getProviderId())){
			return getSampleValueInMSSQL(profile, jdbcType);
		}
		return UNSUPPORTED_PROFILE;
	}
	
	private String getJavaTypeTemporary(IConnectionProfile profile, int jdbcType){
		switch (jdbcType){
		case Types.BINARY:
		case Types.VARBINARY:
		case Types.LONGVARBINARY:
		case Types.BLOB:
			return "byte[]";
		case Types.BIT:
		case Types.BOOLEAN:
			return "boolean";
		case Types.TINYINT:
		case Types.SMALLINT:
			return "short";
		case Types.INTEGER:
			return "int";
		case Types.BIGINT:
			return "long";
		case Types.REAL:
		case Types.FLOAT:
			return "float";
		case Types.DOUBLE:
			return "double";
		case Types.DECIMAL:
		case Types.NUMERIC:
			return "java.math.BigDecimal";
		case Types.TIME:
			return "java.sql.Time";
		case Types.DATE:
			return "java.sql.Date";
		case Types.TIMESTAMP:
			return "java.sql.Timestamp";
		case Types.CLOB:
		case Types.VARCHAR:
		case Types.NVARCHAR:
			return "String";
		case Types.CHAR:
			return "char";
		default:
			return "String";
		}
	}
	private String getSampleValueInMSSQL(IConnectionProfile profile,
			int jdbcType) {
		return getJavaTypeTemporary(profile, jdbcType);
	}
	private String getJavaTypeByMySQL(IConnectionProfile profile, int jdbcType) {
		return getJavaTypeTemporary(profile, jdbcType);
	}
	private String getJavaTypeByOracle(IConnectionProfile profile, int jdbcType) {
		return getJavaTypeTemporary(profile, jdbcType);
	}
	@Override
	public String getSelectKeySampleSql(IConnectionProfile profile) {
		if (PROFILE_ORACLE.equals(profile.getProviderId())){
			return "SELECT YOURSEQ.NEXTVAL AS VALUE FROM DUAL";
		}else if (PROFILE_MYSQL.equals(profile.getProviderId())){
			return "select @@IDENTITY as value";
		}
		return "??";
	}

}
